home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / game / shoot / ADescentSrc.lha / descent / main / menu.c < prev    next >
C/C++ Source or Header  |  1998-11-09  |  31KB  |  1,141 lines

  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  12. */
  13. /*
  14.  * $Source: /usr/CVS/descent/main/menu.c,v $
  15.  * $Revision: 1.7 $
  16.  * $Author: nobody $
  17.  * $Date: 1998/11/09 22:20:36 $
  18.  *
  19.  * Inferno main menu.
  20.  *
  21.  * 
  22.  *
  23.  */
  24.  
  25. #pragma off (unreferenced)
  26. static char rcsid[] = "$Id: menu.c,v 1.7 1998/11/09 22:20:36 nobody Exp $";
  27. #pragma on (unreferenced)
  28.  
  29. #include <time.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <stdarg.h>
  35. #include <errno.h>
  36.  
  37. #include "menu.h"
  38. #include "inferno.h"
  39. #include "game.h"
  40. #include "gr.h"
  41. #include "key.h"
  42. #include "iff.h"
  43. #include "mem.h"
  44. #include "error.h"
  45. #include "bm.h"
  46. #include "screens.h"
  47. #include "mono.h"
  48. #include "cflib.h"
  49. #include "joy.h"
  50. #include "vecmat.h"
  51. #include "effects.h"
  52. #include "slew.h"
  53. #include "gamemine.h"
  54. #include "gamesave.h"
  55. #include "palette.h"
  56. #include "args.h"
  57. #include "newdemo.h"
  58. #include "timer.h"
  59. #include "sounds.h"
  60. #include "gameseq.h"
  61. #include "text.h"
  62. #include "gamefont.h"
  63. #include "newmenu.h"
  64. #include "network.h"
  65. #include "scores.h"
  66. #include "joydefs.h"
  67. #include "modem.h"
  68. #include "playsave.h"
  69. #include "multi.h"
  70. #include "kconfig.h"
  71. #include "titles.h"
  72. #include "credits.h"
  73. #include "texmap.h"
  74. #include "polyobj.h"
  75. #include "state.h"
  76. #include "mission.h"
  77. #include "songs.h"
  78. #include "config.h"
  79.  
  80. #ifdef EDITOR
  81. #include "editor/editor.h"
  82. #endif
  83.  
  84. #ifdef VIRGIN
  85. #include "VirgeTexture.h"
  86. #endif
  87.  
  88. #ifdef WARP3D
  89. #include "Warp3D.h"
  90. #endif
  91.  
  92. //char *menu_difficulty_text[] = { "Trainee", "Rookie", "Fighter", "Hotshot", "Insane" };
  93. //char *menu_detail_text[] = { "Lowest", "Low", "Medium", "High", "Highest", "", "Custom..." };
  94.  
  95. #define MENU_NEW_GAME            0
  96. #define MENU_GAME                   1 
  97. #define MENU_EDITOR                 2
  98. #define MENU_VIEW_SCORES            3
  99. #define MENU_QUIT                4
  100. #define MENU_LOAD_GAME              5
  101. #define MENU_SAVE_GAME              6
  102. #define MENU_DEMO_PLAY              8
  103. #define MENU_LOAD_LEVEL             9
  104. #define MENU_START_NETGAME          10
  105. #define MENU_JOIN_NETGAME           11
  106. #define MENU_CONFIG                 13
  107. #define MENU_REJOIN_NETGAME     14
  108. #define MENU_DIFFICULTY             15
  109. #define MENU_START_SERIAL           18
  110. #define MENU_HELP                       19
  111. #define MENU_NEW_PLAYER             20
  112. #define MENU_MULTIPLAYER            21
  113. #define MENU_STOP_MODEM             22
  114. #define MENU_SHOW_CREDITS           23
  115. #define MENU_ORDER_INFO             24
  116. #define MENU_PLAY_SONG              25
  117.  
  118. //ADD_ITEM("Start netgame...", MENU_START_NETGAME, -1 );
  119. //ADD_ITEM("Send net message...", MENU_SEND_NET_MESSAGE, -1 );
  120.  
  121. #define ADD_ITEM(t,value,key)  do { m[num_options].type=NM_TYPE_MENU; m[num_options].text=t; menu_choice[num_options]=value;num_options++; } while (0)
  122.  
  123. extern int last_joy_time;       //last time the joystick was used
  124. #define speedtest_on 0
  125.  
  126. ubyte do_auto_demo = 1;         // Flag used to enable auto demo starting in main menu.
  127. int Player_default_difficulty; // Last difficulty level chosen by the player
  128. int Auto_leveling_on = 0;
  129. int Menu_draw_copyright = 0;
  130.  
  131. void autodemo_menu_check(int nitems, newmenu_item * items, int *last_key, int citem )
  132. {
  133.     int curtime;
  134.  
  135.     nitems = nitems;
  136.     items=items;
  137.     citem = citem;
  138.  
  139.     //draw copyright message
  140.     if ( Menu_draw_copyright )      {
  141.         Menu_draw_copyright = 0;
  142.         gr_set_current_canvas(NULL);
  143.         gr_set_curfont(GAME_FONT);
  144.         gr_set_fontcolor(BM_XRGB(6,6,6),-1);
  145.         gr_printf(0x8000,grd_curcanv->cv_bitmap.bm_h-GAME_FONT->ft_h-2,TXT_COPYRIGHT);
  146.         gr_update(NULL);
  147.     }
  148.     
  149.     // Don't allow them to hit ESC in the main menu.
  150.     if (*last_key==KEY_ESC) *last_key = 0;
  151.  
  152.     if ( do_auto_demo ) {
  153.         curtime = timer_get_approx_seconds();
  154.         //if ( ((keyd_time_when_last_pressed+i2f(20)) < curtime) && ((last_joy_time+i2f(20)) < curtime) && (!speedtest_on)  ) {
  155.         if ( ((keyd_time_when_last_pressed+i2f(45)) < curtime) && (!speedtest_on)  ) {
  156.             keyd_time_when_last_pressed = curtime;          // Reset timer so that disk won't thrash if no demos.
  157.             newdemo_start_playback(NULL);       // Randomly pick a file
  158.             if (Newdemo_state == ND_STATE_PLAYBACK) {
  159.                 Function_mode = FMODE_GAME;
  160.                 *last_key = -2;                             
  161.             }
  162.         }
  163.     }
  164. }
  165.  
  166. //static int First_time = 1;
  167. static int main_menu_choice = 0;
  168.  
  169. //  -----------------------------------------------------------------------------
  170. //  Create the main menu.
  171. void create_main_menu(newmenu_item *m, int *menu_choice, int *callers_num_options)
  172. {
  173.     int num_options;
  174.  
  175.     #ifndef DEMO_ONLY
  176.     num_options = 0;
  177.  
  178. //  //  Move down to allow for space to display "Destination Saturn"
  179. //  if (Saturn) {
  180. //      int i;
  181. //
  182. //      for (i=0; i<4; i++)
  183. //          ADD_ITEM("", 0, -1);
  184. //
  185. //      if (First_time) {
  186. //          main_menu_choice = 4;
  187. //          First_time = 0;
  188. //      }
  189. //  }
  190.  
  191.     ADD_ITEM(TXT_NEW_GAME,MENU_NEW_GAME,KEY_N);
  192.  
  193. #ifdef SHAREWARE
  194.     if (get_game_list(NULL)>0)
  195. #endif
  196.  
  197.     ADD_ITEM(TXT_LOAD_GAME,MENU_LOAD_GAME,KEY_L);
  198.  
  199.     ADD_ITEM(TXT_MULTIPLAYER_,MENU_MULTIPLAYER,-1);
  200.  
  201.     ADD_ITEM(TXT_OPTIONS_, MENU_CONFIG, -1 );
  202.     ADD_ITEM(TXT_CHANGE_PILOTS,MENU_NEW_PLAYER,unused);
  203.     ADD_ITEM(TXT_VIEW_DEMO,MENU_DEMO_PLAY,0);
  204.     ADD_ITEM(TXT_VIEW_SCORES,MENU_VIEW_SCORES,KEY_V);
  205.     #ifdef SHAREWARE
  206.     ADD_ITEM(TXT_ORDERING_INFO,MENU_ORDER_INFO,-1);
  207.     #endif
  208.     ADD_ITEM(TXT_CREDITS,MENU_SHOW_CREDITS,-1);
  209.     #endif
  210.     ADD_ITEM(TXT_QUIT,MENU_QUIT,KEY_Q);
  211.  
  212.     #ifndef RELEASE
  213.     if (!(Game_mode & GM_MULTI ))   {
  214.         //m[num_options].type=NM_TYPE_TEXT;
  215.         //m[num_options++].text=" Debug options:";
  216.  
  217.         ADD_ITEM("  Load level...",MENU_LOAD_LEVEL ,KEY_N);
  218.         #ifdef EDITOR
  219.         ADD_ITEM("  Editor", MENU_EDITOR, KEY_E);
  220.         #endif
  221.     }
  222.  
  223.     ADD_ITEM( "  Play song", MENU_PLAY_SONG, -1 );
  224.     #endif
  225.  
  226.     *callers_num_options = num_options;
  227. }
  228.  
  229. //returns number of item chosen
  230. int DoMenu() 
  231. {
  232.     int menu_choice[25];
  233.     newmenu_item m[25];
  234.     int num_options = 0;
  235.  
  236.     if ( Players[Player_num].callsign[0]==0 )   {
  237.         RegisterPlayer();
  238.         return 0;
  239.     }
  240.     
  241.     if ((Game_mode & GM_SERIAL) || (Game_mode & GM_MODEM)) {
  242.         do_option(MENU_START_SERIAL);
  243.         return 0;
  244.     }
  245.  
  246.     create_main_menu(m, menu_choice, &num_options);
  247.     gr_update(NULL);
  248.  
  249.     do {
  250.         keyd_time_when_last_pressed = timer_get_fixed_seconds();        // .. 20 seconds from now!
  251.         if (main_menu_choice < 0 )  main_menu_choice = 0;       
  252.         Menu_draw_copyright = 1;
  253.         main_menu_choice = newmenu_do2( "", NULL, num_options, m, autodemo_menu_check, main_menu_choice, Menu_pcx_name);
  254.         if ( main_menu_choice > -1 ) do_option(menu_choice[main_menu_choice]);
  255.         create_main_menu(m, menu_choice, &num_options); //  may have to change, eg, maybe selected pilot and no save games.
  256.     } while( Function_mode==FMODE_MENU );
  257.  
  258.     if ( Function_mode==FMODE_GAME )    
  259.         gr_palette_fade_out( gr_palette, 32, 0 );
  260.  
  261.     return main_menu_choice;
  262. }
  263.  
  264. extern void show_order_form(void);  // John didn't want this in inferno.h so I just externed it.
  265.  
  266. //returns flag, true means quit menu
  267. void do_option ( int select) 
  268. {
  269.     switch (select) {
  270.         case MENU_NEW_GAME:
  271.             do_new_game_menu();
  272.             break;
  273.         case MENU_GAME:
  274.             break;
  275.         case MENU_DEMO_PLAY:
  276.             { 
  277.                 char demo_file[16];
  278.                 if (newmenu_get_filename( TXT_SELECT_DEMO, "*.dem", demo_file, 1 )) {
  279.                     newdemo_start_playback(demo_file);
  280.                 }
  281.             }
  282.             break;
  283.         case MENU_LOAD_GAME:
  284. #ifdef SHAREWARE
  285.             do_load_game_menu();
  286. #else
  287.             state_restore_all(0);   
  288. #endif
  289.             break;
  290.         #ifdef EDITOR
  291.         case MENU_EDITOR:
  292.             Function_mode = FMODE_EDITOR;
  293.             init_cockpit();
  294.             break;
  295.         #endif
  296.         case MENU_VIEW_SCORES:
  297.             gr_palette_fade_out( gr_palette,32,0 );
  298.             scores_view(-1);
  299.             break;
  300.         #ifdef SHAREWARE
  301.         case MENU_ORDER_INFO:
  302.             show_order_form();
  303.             break;
  304.         #endif
  305.         case MENU_QUIT:
  306.             #ifdef EDITOR
  307.             if (! SafetyCheck()) break;
  308.             #endif
  309.             gr_palette_fade_out( gr_palette,32,0);
  310.             Function_mode = FMODE_EXIT;
  311.             break;
  312.         case MENU_NEW_PLAYER:
  313.             RegisterPlayer();       //1 == allow escape out of menu
  314.             break;
  315.  
  316.         case MENU_HELP:
  317.             do_show_help();
  318.             break;
  319.  
  320.         #ifndef RELEASE
  321.  
  322.         case MENU_PLAY_SONG:    {
  323.                 int i;
  324.                 char * m[MAX_SONGS];
  325.  
  326.                 for (i=0;i<MAX_SONGS;i++) {
  327.                     m[i] = Songs[i].filename;
  328.                 }
  329.                 i = newmenu_listbox( "Select Song", MAX_SONGS, m, 1, NULL );
  330.  
  331.                 if ( i > -1 )   {
  332.                     songs_play_song( i, 0 );
  333.                 }
  334.             }
  335.             break;
  336.         case MENU_LOAD_LEVEL: {
  337.             newmenu_item m;
  338.             char text[10]="\0";
  339.             int new_level_num;
  340.  
  341.             m.type=NM_TYPE_INPUT; m.text_len = 10; m.text = text;
  342.  
  343.             newmenu_do( NULL, "Enter level to load", 1, &m, NULL );
  344.  
  345.             new_level_num = atoi(m.text);
  346.  
  347.             if (new_level_num!=0 && new_level_num>=Last_secret_level && new_level_num<=Last_level)  {
  348.                 gr_palette_fade_out( gr_palette, 32, 0 );
  349.                 StartNewGame(new_level_num);
  350.             }
  351.  
  352.             break;
  353.         }
  354.         #endif
  355.  
  356.  
  357.         case MENU_START_NETGAME:
  358. #ifdef NETWORK
  359. //temp!
  360.             load_mission(0);
  361.             network_start_game();
  362. #endif
  363.             break;
  364.         case MENU_JOIN_NETGAME:
  365. //temp!
  366. #ifdef NETWORK
  367.             load_mission(0);
  368.             network_join_game();
  369. #endif
  370.             break;
  371.         case MENU_START_SERIAL:
  372.             #ifdef NETWORK
  373.             com_main_menu();
  374.             #endif
  375.             break;
  376.         case MENU_MULTIPLAYER:
  377.             do_multi_player_menu();
  378.             break;
  379.         case MENU_CONFIG:
  380.             do_options_menu();
  381.             break;
  382.         case MENU_SHOW_CREDITS:
  383.             gr_palette_fade_out( gr_palette,32,0);
  384.             credits_show(); 
  385.             break;
  386.         default:
  387.             Error("Unknown option %d in do_option",select);
  388.             break;
  389.         }
  390.  
  391. }
  392.  
  393. int do_difficulty_menu()
  394. {
  395.     int s;
  396.     newmenu_item m[5];
  397.  
  398.     m[0].type=NM_TYPE_MENU; m[0].text=MENU_DIFFICULTY_TEXT(0);
  399.     m[1].type=NM_TYPE_MENU; m[1].text=MENU_DIFFICULTY_TEXT(1);
  400.     m[2].type=NM_TYPE_MENU; m[2].text=MENU_DIFFICULTY_TEXT(2);
  401.     m[3].type=NM_TYPE_MENU; m[3].text=MENU_DIFFICULTY_TEXT(3);
  402.     m[4].type=NM_TYPE_MENU; m[4].text=MENU_DIFFICULTY_TEXT(4);
  403.  
  404.     s = newmenu_do1( NULL, TXT_DIFFICULTY_LEVEL, NDL, m, NULL, Difficulty_level);
  405.  
  406.     if (s > -1 )    {
  407.         if (s != Difficulty_level)
  408.         {   
  409.             Player_default_difficulty = s;
  410.             write_player_file();
  411.         }
  412.         Difficulty_level = s;
  413.         mprintf((0, "%s %s %i\n", TXT_DIFFICULTY_LEVEL, TXT_SET_TO, Difficulty_level));
  414.         return 1;
  415.     }
  416.     return 0;
  417. }
  418.  
  419. int Max_debris_objects, Max_objects_onscreen_detailed;
  420. int Max_linear_depth_objects;
  421.  
  422. byte    Object_complexity=2, Object_detail=2;
  423. byte    Wall_detail=2, Wall_render_depth=2, Debris_amount=2, SoundChannels = 2;
  424.  
  425. byte    Render_depths[NUM_DETAIL_LEVELS-1] =                                { 6,  9, 12, 15, 20};
  426. byte    Max_perspective_depths[NUM_DETAIL_LEVELS-1] =                   { 1,  2,  3,  5,  8};
  427. byte    Max_linear_depths[NUM_DETAIL_LEVELS-1] =                            { 3,  5,  7, 10, 17};
  428. byte    Max_linear_depths_objects[NUM_DETAIL_LEVELS-1] =                { 1,  2,  3,  5, 12};
  429. byte    Max_debris_objects_list[NUM_DETAIL_LEVELS-1] =                  { 2,  4,  7, 10, 15};
  430. byte    Max_objects_onscreen_detailed_list[NUM_DETAIL_LEVELS-1] =   { 2,  4,  7, 10, 15};
  431. byte    Smts_list[NUM_DETAIL_LEVELS-1] =                                        { 2,  4,  8, 16, 50};   //  threshold for models to go to lower detail model, gets multiplied by obj->size
  432. byte    Max_sound_channels[NUM_DETAIL_LEVELS-1] =                           { 2,  4,  8, 12, 16};
  433.  
  434. //  -----------------------------------------------------------------------------
  435. //  Set detail level based stuff.
  436. //  Note: Highest detail level (detail_level == NUM_DETAIL_LEVELS-1) is custom detail level.
  437. void set_detail_level_parameters(int detail_level)
  438. {
  439.     Assert((detail_level >= 0) && (detail_level < NUM_DETAIL_LEVELS));
  440.  
  441.     if (detail_level < NUM_DETAIL_LEVELS-1) {
  442.         Render_depth = Render_depths[detail_level];
  443.         Max_perspective_depth = Max_perspective_depths[detail_level];
  444.         Max_linear_depth = Max_linear_depths[detail_level];
  445.         Max_linear_depth_objects = Max_linear_depths_objects[detail_level];
  446.  
  447.         Max_debris_objects = Max_debris_objects_list[detail_level];
  448.         Max_objects_onscreen_detailed = Max_objects_onscreen_detailed_list[detail_level];
  449.  
  450.         Simple_model_threshhold_scale = Smts_list[detail_level];
  451.  
  452.         digi_set_max_channels( Max_sound_channels[ detail_level ] );
  453.  
  454.         //  Set custom menu defaults.
  455.         Object_complexity = detail_level;
  456.         Wall_render_depth = detail_level;
  457.         Object_detail = detail_level;
  458.         Wall_detail = detail_level;
  459.         Debris_amount = detail_level;
  460.         SoundChannels = detail_level;
  461.  
  462.     }
  463. }
  464.  
  465. //  -----------------------------------------------------------------------------
  466. void do_detail_level_menu(void)
  467. {
  468.     int s;
  469.     newmenu_item m[7];
  470.  
  471.     m[0].type=NM_TYPE_MENU; m[0].text=MENU_DETAIL_TEXT(0);
  472.     m[1].type=NM_TYPE_MENU; m[1].text=MENU_DETAIL_TEXT(1);
  473.     m[2].type=NM_TYPE_MENU; m[2].text=MENU_DETAIL_TEXT(2);
  474.     m[3].type=NM_TYPE_MENU; m[3].text=MENU_DETAIL_TEXT(3);
  475.     m[4].type=NM_TYPE_MENU; m[4].text=MENU_DETAIL_TEXT(4);
  476.     m[5].type=NM_TYPE_TEXT; m[5].text="";
  477.     m[6].type=NM_TYPE_MENU; m[6].text=MENU_DETAIL_TEXT(5);
  478.  
  479.     s = newmenu_do1( NULL, TXT_DETAIL_LEVEL , NDL+2, m, NULL, Detail_level);
  480.  
  481.     if (s > -1 )    {
  482.         switch (s)  {
  483.             case 0:
  484.             case 1:
  485.             case 2:
  486.             case 3:
  487.             case 4:
  488.                 Detail_level = s;
  489.                 mprintf((0, "Detail level set to %i\n", Detail_level));
  490.                 set_detail_level_parameters(Detail_level);
  491.                 break;
  492.             case 6:
  493.                 Detail_level = 5;
  494.                 do_detail_level_menu_custom();
  495.                 break;
  496.         }
  497.     }
  498.  
  499. }
  500.  
  501. //  -----------------------------------------------------------------------------
  502. void do_detail_level_menu_custom_menuset(int nitems, newmenu_item * items, int *last_key, int citem )
  503. {
  504.     nitems = nitems;
  505.     *last_key = *last_key;
  506.     citem = citem;
  507.  
  508.     Object_complexity = items[0].value;
  509.     Object_detail = items[1].value;
  510.     Wall_detail = items[2].value;
  511.     Wall_render_depth = items[3].value;
  512.     Debris_amount = items[4].value;
  513.     SoundChannels = items[5].value;
  514.  
  515. }
  516.  
  517. void set_custom_detail_vars(void)
  518. {
  519.     Render_depth = Render_depths[Wall_render_depth];
  520.  
  521.     Max_perspective_depth = Max_perspective_depths[Wall_detail];
  522.     Max_linear_depth = Max_linear_depths[Wall_detail];
  523.  
  524.     Max_debris_objects = Max_debris_objects_list[Debris_amount];
  525.  
  526.     Max_objects_onscreen_detailed = Max_objects_onscreen_detailed_list[Object_complexity];
  527.     Simple_model_threshhold_scale = Smts_list[Object_complexity];
  528.     Max_linear_depth_objects = Max_linear_depths_objects[Object_detail];
  529.  
  530.     digi_set_max_channels( Max_sound_channels[ SoundChannels ] );
  531. }
  532.  
  533. //  -----------------------------------------------------------------------------
  534. void do_detail_level_menu_custom(void)
  535. {
  536.     int s=0;
  537.     newmenu_item m[7];
  538.  
  539.     do {
  540.         m[0].type = NM_TYPE_SLIDER;
  541.         m[0].text = TXT_OBJ_COMPLEXITY;
  542.         m[0].value = Object_complexity;
  543.         m[0].min_value = 0;
  544.         m[0].max_value = NDL-1;
  545.  
  546.         m[1].type = NM_TYPE_SLIDER;
  547.         m[1].text = TXT_OBJ_DETAIL;
  548.         m[1].value = Object_detail;
  549.         m[1].min_value = 0;
  550.         m[1].max_value = NDL-1;
  551.  
  552.         m[2].type = NM_TYPE_SLIDER;
  553.         m[2].text = TXT_WALL_DETAIL;
  554.         m[2].value = Wall_detail;
  555.         m[2].min_value = 0;
  556.         m[2].max_value = NDL-1;
  557.  
  558.         m[3].type = NM_TYPE_SLIDER;
  559.         m[3].text = TXT_WALL_RENDER_DEPTH;
  560.         m[3].value = Wall_render_depth;
  561.         m[3].min_value = 0;
  562.         m[3].max_value = NDL-1;
  563.  
  564.         m[4].type = NM_TYPE_SLIDER;
  565.         m[4].text= TXT_DEBRIS_AMOUNT;
  566.         m[4].value = Debris_amount;
  567.         m[4].min_value = 0;
  568.         m[4].max_value = NDL-1;
  569.  
  570.         m[5].type = NM_TYPE_SLIDER;
  571.         m[5].text= TXT_SOUND_CHANNELS;
  572.         m[5].value = SoundChannels;
  573.         m[5].min_value = 0;
  574.         m[5].max_value = NDL-1;
  575.  
  576.         m[6].type = NM_TYPE_TEXT;
  577.         m[6].text= TXT_LO_HI;
  578.  
  579.         s = newmenu_do1( NULL, TXT_DETAIL_CUSTOM, 7, m, do_detail_level_menu_custom_menuset, s);
  580.     } while (s > -1);
  581.  
  582.     set_custom_detail_vars();
  583. }
  584.  
  585. do_new_game_menu()
  586. {
  587.     int n_missions,new_level_num,player_highest_level;
  588.  
  589. #ifndef SHAREWARE
  590.     n_missions = build_mission_list(0);
  591.  
  592.     if (n_missions > 1) {
  593.         int new_mission_num,i, default_mission;
  594.         char * m[MAX_MISSIONS];
  595.  
  596.         default_mission = 0;
  597.         for (i=0;i<n_missions;i++) {
  598.             m[i] = Mission_list[i].mission_name;
  599.             if ( !stricmp( m[i], config_last_mission ) )    
  600.                 default_mission = i;
  601.         }
  602.  
  603.         new_mission_num = newmenu_listbox1( "New Game\n\nSelect mission", n_missions, m, 1, default_mission, NULL );
  604.         gr_update(NULL);
  605.  
  606.         if (new_mission_num == -1)
  607.             return;     //abort!
  608.  
  609.         strcpy(config_last_mission, m[new_mission_num]  );
  610.         
  611.         if (!load_mission(new_mission_num)) {
  612.             nm_messagebox( NULL, 1, TXT_OK, "Error in Mission file"); 
  613.             return;
  614.         }
  615.     }
  616. #endif
  617.  
  618.     new_level_num = 1;
  619.  
  620.     player_highest_level = get_highest_level();
  621.  
  622.     if (player_highest_level > Last_level)
  623.         player_highest_level = Last_level;
  624.  
  625.     if (player_highest_level > 1) {
  626.         newmenu_item m[2];
  627.         char info_text[80];
  628.         char num_text[10];
  629.         int choice;
  630.  
  631. try_again:
  632.         sprintf(info_text,"%s %d",TXT_START_ANY_LEVEL, player_highest_level);
  633.  
  634.         m[0].type=NM_TYPE_TEXT; m[0].text = info_text;
  635.         m[1].type=NM_TYPE_INPUT; m[1].text_len = 10; m[1].text = num_text;
  636.  
  637.         strcpy(num_text,"1");
  638.  
  639.         choice = newmenu_do( NULL, TXT_SELECT_START_LEV, 2, &m, NULL );
  640.  
  641.         if (choice==-1 || m[1].text[0]==0)
  642.             return;
  643.  
  644.         new_level_num = atoi(m[1].text);
  645.  
  646.         if (!(new_level_num>0 && new_level_num<=player_highest_level)) {
  647.             m[0].text = TXT_ENTER_TO_CONT;
  648.             nm_messagebox( NULL, 1, TXT_OK, TXT_INVALID_LEVEL); 
  649.             goto try_again;
  650.         }
  651.     }
  652.  
  653.     Difficulty_level = Player_default_difficulty;
  654.  
  655.     if (!do_difficulty_menu())
  656.         return;
  657. #ifdef VIRGIN
  658.     MakeBitValues();
  659. #endif
  660. #ifdef WARP3D
  661.     WARP_MakeBitValues();
  662. #endif
  663.     gr_palette_fade_out( gr_palette, 32, 0 );
  664. #ifdef PSX_BUILD_TOOLS
  665.     {
  666.         int i;
  667.         for (i=Last_secret_level; i<=Last_level; i++ )  {
  668.             if ( i!=0 ) 
  669.                 StartNewGame(i);
  670.         }       
  671.     }
  672. #endif
  673.  
  674.     StartNewGame(new_level_num);
  675.  
  676. }
  677.  
  678. do_load_game_menu()
  679. {
  680.     newmenu_item m[N_SAVE_SLOTS];
  681.     char *saved_text[N_SAVE_SLOTS];
  682.     int i,choice;
  683.  
  684.     get_game_list(saved_text);
  685.  
  686.     for (i=0;i<N_SAVE_SLOTS;i++) {
  687.  
  688.         if (saved_text[i][0]) {
  689.             m[i].type = NM_TYPE_MENU;
  690.             m[i].text = saved_text[i];
  691.         }
  692.         else {
  693.             m[i].type = NM_TYPE_TEXT;
  694.             m[i].text = TXT_EMPTY;
  695.         }
  696.     }
  697.  
  698.     choice = newmenu_do( NULL, TXT_LOAD_GAME, N_SAVE_SLOTS, m, NULL );
  699.  
  700.     if (choice != -1) {
  701.         int ret;
  702.  
  703.         if ((ret=load_player_game(choice)) == 0)
  704.             ResumeSavedGame(Players[Player_num].level);
  705.         else {
  706.             newmenu_item m1[3];
  707.  
  708.             m1[0].type = NM_TYPE_TEXT;  m1[0].text = strerror(ret);
  709.             m1[1].type = NM_TYPE_TEXT;  m1[1].text = "";
  710.             m1[2].type = NM_TYPE_TEXT;  m1[2].text = TXT_ENTER_TO_CONT;
  711.  
  712.             newmenu_do( NULL, TXT_ERR_LOADING_GAME, 3, m1, NULL );
  713.  
  714.         }
  715.     }
  716. }
  717.  
  718. do_save_game_menu()
  719. {
  720.     newmenu_item m[N_SAVE_SLOTS];
  721.     char *saved_text_ptrs[N_SAVE_SLOTS];
  722.     char menu_text[N_SAVE_SLOTS][GAME_NAME_LEN+1];      //+1 for terminating zero
  723.     int i,choice;
  724.  
  725.     get_game_list(saved_text_ptrs);
  726.  
  727.     for (i=0;i<N_SAVE_SLOTS;i++) {
  728.  
  729.         strcpy(menu_text[i],saved_text_ptrs[i]);
  730.  
  731.         m[i].type = NM_TYPE_INPUT_MENU;
  732.         m[i].text_len = GAME_NAME_LEN;
  733.         m[i].text = menu_text[i];
  734.  
  735.         if (!menu_text[i][0])
  736.             strcpy(menu_text[i],TXT_EMPTY);
  737.  
  738.     }
  739.  
  740.     choice = newmenu_do( NULL, TXT_SAVE_GAME_SLOTS, N_SAVE_SLOTS, m, NULL );
  741.  
  742.     if (choice != -1) {
  743.         int ret;
  744.  
  745.         if ((ret=save_player_game(choice,m[choice].text)) != 0)
  746.             nm_messagebox( NULL,1, TXT_CONTINUE,"%s\n%s\n\n", TXT_SAVE_ERROR, strerror(ret));
  747.     }
  748.  
  749. }
  750.  
  751. extern void GameLoop(int, int );
  752.  
  753. void joydef_menuset(int nitems, newmenu_item * items, int *last_key, int citem )
  754. {
  755.     nitems=nitems;      
  756.     *last_key = *last_key;
  757.  
  758.     if ( citem==4)  {
  759.         gr_palette_set_gamma(items[4].value);
  760.     }
  761.  
  762.     if ( Config_digi_volume != items[0].value ) {
  763.         Config_digi_volume = items[0].value;
  764.         digi_set_digi_volume( (Config_digi_volume*32768)/8 );
  765.         digi_play_sample_once( SOUND_DROP_BOMB, F1_0 );
  766.  
  767.     }
  768.  
  769.     if (Config_midi_volume != items[1].value )  {
  770.         Config_midi_volume = items[1].value;
  771.         digi_set_midi_volume( (Config_midi_volume*128)/8 );
  772.     }
  773. }
  774.  
  775. //this change was made in DESCENT.TEX, but since we're not including that
  776. //file in the v1.1 update, we're making the change in the code here also
  777. #ifdef SHAREWARE
  778. #undef  TXT_JOYS_SENSITIVITY
  779. #define TXT_JOYS_SENSITIVITY "Joystick/Mouse\nSensitivity"
  780. #endif
  781.  
  782. #ifdef VIRGIN
  783. void do_virge_fps_menu(void)
  784. {
  785.     newmenu_item m[4];
  786.     extern int VirgeFPSLimit;
  787.     int item;
  788.  
  789.     m[0].type = NM_TYPE_CHECK;  m[0].text = "Limit FPS Rate";
  790.     m[1].type = NM_TYPE_TEXT;   m[1].text = "Max FPS Rate:";
  791.     m[2].type = NM_TYPE_NUMBER; m[2].text = "Frames/sec";   m[2].value = VirgeFPSLimit;
  792.         m[2].min_value = 5; m[2].max_value=40;
  793.  
  794.     if (VirgeFPSLimit > 0) m[0].value = 1;
  795.     else                   m[0].value = 0;
  796.  
  797.     item = newmenu_do("FPS Blocker", "ESC to cancel", 3, m, NULL);
  798.  
  799.     if (item>-1) {
  800.         if (m[0].value == 0) {
  801.             VirgeSetFPSLimit(0);
  802.             return;
  803.         }
  804.         VirgeSetFPSLimit(m[2].value);
  805.     }
  806. }
  807.  
  808. void do_virge_menu(void)
  809. {
  810.     newmenu_item m[10];
  811.     int nitems;
  812.     int i=0;
  813.  
  814.     extern int VirgeFilter;
  815.     extern int VirgeTMapper;
  816.     extern int VirgeModulateLight;
  817.  
  818. loop:
  819.     m[0].type = NM_TYPE_CHECK;  m[0].text = "Bilinear Filtering";           m[0].value = VirgeFilter;
  820.     m[1].type = NM_TYPE_CHECK;  m[1].text = "Flashing Light";               m[1].value = VirgeModulateLight;
  821.     m[2].type = NM_TYPE_TEXT;   m[2].text = "Texture Mapper";
  822.     m[3].type = NM_TYPE_RADIO;  m[3].text = "SubPixel Mapper (req. FPU)";   m[3].value = 0; m[3].group = 0;
  823.     m[4].type = NM_TYPE_RADIO;  m[4].text = "FullPixel Mapper";             m[4].value = 0; m[4].group = 0;
  824.     m[5].type = NM_TYPE_RADIO;  m[5].text = "SubPixel Persp. (req. FPU)";   m[5].value = 0; m[5].group = 0;
  825.     m[6].type = NM_TYPE_TEXT;   m[6].text = "Other options...";
  826.     m[7].type = NM_TYPE_MENU;   m[7].text = "FPS Limiter...";
  827.  
  828.     switch(VirgeTMapper) {
  829.     case 0:
  830.         m[3].value = 1; m[4].value = 0; m[5].value = 0;
  831.         break;
  832.     case 1:
  833.         m[3].value = 0; m[4].value = 1; m[5].value = 0;
  834.         break;
  835.     case 2:
  836.         m[3].value = 0; m[4].value = 0; m[5].value = 1;
  837.         break;
  838.     }
  839.  
  840.     nitems = 8;
  841.     i = newmenu_do1("ViRGE Menu", "ESC to cancel", nitems, m,NULL ,i);
  842.  
  843.     if (i==-1) return;
  844.  
  845.     if (i==7) {
  846.         do_virge_fps_menu();
  847.         goto loop;
  848.     }
  849.  
  850.     if (m[0].value == 1) VirgeBilinearOn();
  851.     else                 VirgeBilinearOff();
  852.  
  853.     VirgeSetModulate(m[1].value);
  854.  
  855.     if      (m[3].value == 1) VirgeSetMapper(0);    // SubPixels/FPU
  856.     else if (m[4].value == 1) VirgeSetMapper(1);    // FullPixels/INT
  857.     else if (m[5].value == 1) VirgeSetMapper(2);    // SubPixelsPerp/FPU
  858.     else                      VirgeSetMapper(-1);    // Default
  859.  
  860. }
  861. #endif
  862.  
  863. #ifdef WARP3D
  864. void do_warp_filter_menu(void)
  865. {
  866.     newmenu_item m[10];
  867.     int i = 0, j = 0;
  868.  
  869.     do {
  870.         m[0].type = NM_TYPE_TEXT;  m[0].text = "Texture";
  871.         m[1].type = NM_TYPE_RADIO; m[1].text = "Nearest";   m[1].group = 0;
  872.         m[2].type = NM_TYPE_RADIO; m[2].text = "Linear";    m[2].group = 0;
  873.         m[3].type = NM_TYPE_TEXT;  m[3].text = "Depth";
  874.         m[4].type = NM_TYPE_RADIO; m[4].text = "Nearest";   m[4].group = 1;
  875.         m[5].type = NM_TYPE_RADIO; m[5].text = "Linear";    m[5].group = 1;
  876.  
  877.         switch (WARP_Filter) {
  878.             case 0: m[1].value = 1;
  879.                     m[2].value = 0;
  880.                     break;
  881.             case 1: m[1].value = 0;
  882.                     m[2].value = 1;
  883.                     break;
  884.         }
  885.  
  886.         switch (WARP_Depth) {
  887.             case 0: m[4].value = 1;
  888.                     m[5].value = 0;
  889.                     break;
  890.             case 1: m[4].value = 0;
  891.                     m[5].value = 1;
  892.                     break;
  893.         }
  894.  
  895.         i = newmenu_do1( "Filtering", NULL,  6, m, 0, i );
  896.         if (i == -1) break;
  897.  
  898.         if (m[1].value == 1) WARP_Filter = 0;
  899.         else                 WARP_Filter = 1;
  900.  
  901.         if (m[4].value == 1) WARP_Depth = 0;
  902.         else                 WARP_Depth = 1;
  903.  
  904.  
  905.     } while (i > -1);
  906.  
  907.     WARP_UpdateTextureCache();
  908. }
  909.  
  910. void do_warp_texture_menu(void)
  911. {
  912.     newmenu_item m[10];
  913.     int i = 0;
  914.     ULONG oldmipmap = WARP_MipMap;
  915.  
  916.     do {
  917.         m[0].type = NM_TYPE_RADIO; m[0].text = "Perspective";   m[0].group = 0;
  918.         m[1].type = NM_TYPE_RADIO; m[1].text = "Linear";        m[1].group = 0;
  919.         m[2].type = NM_TYPE_CHECK; m[2].text = "Mapping";       m[2].value = WARP_TMap;
  920.         m[3].type = NM_TYPE_CHECK; m[3].text = "MipMapping";    m[3].value = WARP_MipMap;
  921.         m[4].type = NM_TYPE_SLIDER; m[4].text ="LightFX";       m[4].value = (int)WARP_MFactor; m[4].min_value = 0; m[4].max_value = 8;
  922.  
  923.         if (WARP_Persp == 1) {
  924.             m[0].value = 1;
  925.             m[1].value = 0;
  926.         } else {
  927.             m[0].value = 0;
  928.             m[1].value = 1;
  929.         }
  930.  
  931.         i = newmenu_do1( NULL, "Texture Mapping", 5, m, 0, i );
  932.         if (i == -1) break;
  933.  
  934.         switch (i) {
  935.             case 0: WARP_Persp = 1;
  936.                     break;
  937.             case 1: WARP_Persp = 0;
  938.                     break;
  939.             case 2: WARP_TMap = m[2].value;
  940.                     break;
  941.             case 3: WARP_MipMap = m[3].value;
  942.                     break;
  943.             case 4: WARP_MFactor = (W3D_Float)m[4].value;
  944.                     break;
  945.         }
  946.  
  947.     } while (i > -1);
  948.  
  949.     WARP_TMap = m[2].value;
  950.     WARP_MipMap = m[3].value;
  951.  
  952.     if (WARP_MipMap != oldmipmap) {     //  Need to remake the texture cache
  953.         show_boxed_message("Remaking textures");
  954.         WARP_DeleteTextureCache();
  955.         WARP_InitTextureCache();
  956.         WARP_UpdateTextureCache();
  957.         clear_boxed_message();
  958.     }
  959.     WARP_MFactor = (W3D_Float)m[4].value;
  960.     if (WARP_MFactor == 0.0) WARP_Modulate = 0;
  961.     else                     WARP_Modulate = 1;
  962.  
  963.     WARP_UpdateState();
  964. }
  965.  
  966. void do_warp_detail_menu(void)
  967. {
  968.     newmenu_item m[12];
  969.     int i = 0;
  970.  
  971.     m[0].type = NM_TYPE_SLIDER; m[0].text="Textures";   m[0].value = WARP_HTMap; m[0].min_value = 0; m[0].max_value = 2;
  972.     m[1].type = NM_TYPE_SLIDER; m[1].text="MipMaps";    m[1].value = WARP_HMMap; m[1].min_value = 0; m[1].max_value = 2;
  973.     m[2].type = NM_TYPE_SLIDER; m[2].text="Bi-Filter";  m[2].value = WARP_HBif;  m[2].min_value = 0; m[2].max_value = 2;
  974.     m[3].type = NM_TYPE_SLIDER; m[3].text="D-Filter";   m[3].value = WARP_HDf;   m[3].min_value = 0; m[3].max_value = 2;
  975.     m[4].type = NM_TYPE_SLIDER; m[4].text="Perspective";m[4].value = WARP_HPers; m[4].min_value = 0; m[4].max_value = 2;
  976.     m[5].type = NM_TYPE_SLIDER; m[5].text="Blending";   m[5].value = WARP_HBlend;m[5].min_value = 0; m[5].max_value = 2;
  977.     m[6].type = NM_TYPE_SLIDER; m[6].text="Fogging";    m[6].value = WARP_HFog;  m[6].min_value = 0; m[6].max_value = 2;
  978.     m[7].type = NM_TYPE_SLIDER; m[7].text="Anitalias";  m[7].value = WARP_HAnti; m[7].min_value = 0; m[7].max_value = 2;
  979.     m[8].type = NM_TYPE_SLIDER; m[8].text="Dithering";  m[8].value = WARP_HDith; m[8].min_value = 0; m[8].max_value = 2;
  980.     m[9].type = NM_TYPE_TEXT;   m[9].text="             LO HI";
  981.  
  982.     i = newmenu_do1( NULL, "Details", 10, m, 0, i );
  983.  
  984.     WARP_HTMap = m[0].value;
  985.     WARP_HMMap = m[1].value;
  986.     WARP_HBif  = m[2].value;
  987.     WARP_HDf   = m[3].value;
  988.     WARP_HPers = m[4].value;
  989.     WARP_HBlend= m[5].value;
  990.     WARP_HFog  = m[6].value;
  991.     WARP_HAnti = m[7].value;
  992.     WARP_HDith = m[8].value;
  993.  
  994.     WARP_UpdateHints();
  995.     WARP_UpdateTextureCache();
  996. }
  997.  
  998.  
  999. void do_warp_fog_menu(void)
  1000. {
  1001.     newmenu_item m[10];
  1002.     int i = 0;
  1003.     char text[5][30];
  1004.  
  1005.     sprintf( text[0], "%d", (int)(WARP_FogParam.fog_start * 100));
  1006.     sprintf( text[1], "%d", (int)(WARP_FogParam.fog_end * 100));
  1007.     sprintf( text[2], "%d", (int)(WARP_FogParam.fog_color.r * 255));
  1008.     sprintf( text[3], "%d", (int)(WARP_FogParam.fog_color.g * 255));
  1009.     sprintf( text[4], "%d", (int)(WARP_FogParam.fog_color.b * 255));
  1010.  
  1011.     do {
  1012.         m[0].type = NM_TYPE_CHECK; m[0].text = "Fog on"; m[0].value = WARP_Fog;
  1013.         m[1].type = NM_TYPE_TEXT;  m[1].text = "Fog start/end";
  1014.         m[2].type = NM_TYPE_INPUT; m[2].text = text[0];  m[2].text_len = 20;
  1015.         m[3].type = NM_TYPE_INPUT; m[3].text = text[1];  m[3].text_len = 20;
  1016.         m[4].type = NM_TYPE_TEXT;  m[4].text = " ";
  1017.         m[5].type = NM_TYPE_TEXT;  m[5].text = "Fog color";
  1018.         m[6].type = NM_TYPE_INPUT; m[6].text = text[2];  m[6].text_len = 20;
  1019.         m[7].type = NM_TYPE_INPUT; m[7].text = text[3];  m[7].text_len = 20;
  1020.         m[8].type = NM_TYPE_INPUT; m[8].text = text[4];  m[8].text_len = 20;
  1021.  
  1022.         i = newmenu_do1( NULL, "Fogging", 9, m, 0, i );
  1023.         if (i == -1) break;
  1024.  
  1025.         WARP_Fog = m[0].value;
  1026.  
  1027.     } while (i>-1);
  1028.  
  1029.     WARP_Fog = m[0].value;
  1030.     WARP_FogParam.fog_start = atof(text[0]) / 100.0;
  1031.     WARP_FogParam.fog_end = atof(text[1]) / 100.0;
  1032.     WARP_FogParam.fog_color.r = atof(text[2]) / 255.0;
  1033.     WARP_FogParam.fog_color.g = atof(text[3]) / 255.0;
  1034.     WARP_FogParam.fog_color.b = atof(text[4]) / 255.0;
  1035.  
  1036.     WARP_UpdateFog();
  1037. }
  1038.  
  1039. void do_warp_menu(void)
  1040. {
  1041.     newmenu_item m[10];
  1042.     int i = 0;
  1043.  
  1044.     do {
  1045.         m[0].type = NM_TYPE_MENU; m[0].text = "Filter options...";
  1046.         m[1].type = NM_TYPE_MENU; m[1].text = "Texture options...";
  1047.         m[2].type = NM_TYPE_MENU; m[2].text = "Fogging options...";
  1048.         m[3].type = NM_TYPE_MENU; m[3].text = "Warp detail options...";
  1049.  
  1050.         i = newmenu_do1( "Warp3D options", NULL, 4, m, 0, i );
  1051.  
  1052.         switch (i) {
  1053.             case 0: do_warp_filter_menu();  break;
  1054.             case 1: do_warp_texture_menu(); break;
  1055.             case 2: do_warp_fog_menu();     break;
  1056.             case 3: do_warp_detail_menu();  break;
  1057.         }
  1058.     } while (i > -1);
  1059. }
  1060. #endif
  1061. void do_options_menu()
  1062. {
  1063.     newmenu_item m[13];
  1064.     int i = 0;
  1065.  
  1066.     do {
  1067.         m[0].type = NM_TYPE_SLIDER; m[0].text=TXT_FX_VOLUME; m[0].value=Config_digi_volume;m[0].min_value=0; m[0].max_value=8; 
  1068.         m[1].type = NM_TYPE_SLIDER; m[1].text=TXT_MUSIC_VOLUME; m[1].value=Config_midi_volume;m[1].min_value=0; m[1].max_value=8; 
  1069.         m[2].type = NM_TYPE_CHECK; m[2].text=TXT_REVERSE_STEREO; m[2].value=Config_channels_reversed; 
  1070.         m[3].type = NM_TYPE_TEXT; m[3].text="";
  1071.         m[4].type = NM_TYPE_SLIDER; m[4].text=TXT_BRIGHTNESS; m[4].value=gr_palette_get_gamma();m[4].min_value=0; m[4].max_value=8; 
  1072.         m[5].type = NM_TYPE_TEXT; m[5].text="";
  1073.         m[6].type = NM_TYPE_MENU; m[6].text=TXT_CONTROLS_;
  1074.         m[7].type = NM_TYPE_MENU; m[7].text=TXT_DETAIL_LEVELS;
  1075.         m[8].type = NM_TYPE_MENU; m[8].text=TXT_CAL_JOYSTICK;
  1076.     #if !defined(VIRGIN) && !defined(WARP3D)
  1077.         m[9].type = NM_TYPE_TEXT; m[9].text="";
  1078.     #elif defined(VIRIGN)
  1079.         m[9].type = NM_TYPE_MENU; m[9].text="ViRGE options...";
  1080.     #else defined(WARP3D)
  1081.         m[9].type = NM_TYPE_MENU; m[9].text="WARP3D options...";
  1082.     #endif
  1083.         m[10].type = NM_TYPE_SLIDER; m[10].text=TXT_JOYS_SENSITIVITY; m[10].value=Config_joystick_sensitivity; m[10].min_value =0; m[10].max_value = 8;
  1084.         m[11].type = NM_TYPE_TEXT; m[11].text="";
  1085.         m[12].type = NM_TYPE_CHECK; m[12].text="Ship auto-leveling"; m[12].value=Auto_leveling_on; 
  1086.                 
  1087.         i = newmenu_do1( NULL, TXT_OPTIONS, 13, m, joydef_menuset, i );
  1088.             
  1089.         switch(i)   {
  1090.             case 6: joydefs_config();           break;
  1091.             case 7: do_detail_level_menu(); break;
  1092.             case 8: joydefs_calibrate();        break;
  1093.             #ifdef VIRGIN
  1094.             case 9: do_virge_menu();        break;
  1095.             #endif
  1096.             #ifdef WARP3D
  1097.             case 9: do_warp_menu();         break;
  1098.             #endif
  1099.         }
  1100.  
  1101.         Config_channels_reversed = m[2].value;
  1102.         Config_joystick_sensitivity = m[10].value;
  1103.         Auto_leveling_on = m[12].value;
  1104.     } while( i>-1 );
  1105.  
  1106.     if ( Config_midi_volume < 1 )   {
  1107.         digi_play_midi_song( NULL, NULL, NULL, 0 );
  1108.     }
  1109.  
  1110.     write_player_file();
  1111. }
  1112.  
  1113. void do_multi_player_menu()
  1114. {
  1115.     int menu_choice[3];
  1116.     newmenu_item m[3];
  1117.     int choice = 0, num_options = 0;
  1118.     int old_game_mode;
  1119.  
  1120.     do {
  1121.         old_game_mode = Game_mode;
  1122.         num_options = 0;
  1123.  
  1124.         ADD_ITEM(TXT_START_NET_GAME, MENU_START_NETGAME, -1 );
  1125.         ADD_ITEM(TXT_JOIN_NET_GAME, MENU_JOIN_NETGAME, -1 );
  1126.         ADD_ITEM(TXT_MODEM_GAME, MENU_START_SERIAL, -1);
  1127.  
  1128.         choice = newmenu_do1( NULL, TXT_MULTIPLAYER, num_options, m, NULL, choice );
  1129.         
  1130.         if ( choice > -1 )  
  1131.             do_option(menu_choice[choice]);
  1132.     
  1133.         if (old_game_mode != Game_mode)
  1134.             break;      // leave menu
  1135.  
  1136.     } while( choice > -1 );
  1137.  
  1138. }
  1139.  
  1140.  
  1141.